package com.ydj.framework.utils;

import cn.hutool.core.lang.Pair;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import okio.BufferedSink;
import okio.Okio;
import okio.Sink;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.net.URLEncoder;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.zip.GZIPInputStream;

@Slf4j
public class OkHttpClientUtils {

    private static final MediaType MEDIA_TYPE_JSON = MediaType.parse("application/json; charset=utf-8");

    private static final MediaType MEDIA_TYPE_XMl = MediaType.parse("application/xml; charset=utf-8");

    public static final MediaType FORM_CONTENT_TYPE = MediaType.parse("application/x-www-form-urlencoded; charset=utf-8");

    public static String get(String url) {
        return get(url, null, null);
    }

	public static byte[] getForBytes(String url) {
		return getForBytes(url, null, null);
	}

    /**
     * @param readTime 超时时间
     * @return 返回内容
     */
    public static String get(String url, Map<String, String> headers, Long readTime) {
        Response response = null;
        try {
            OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder();
            if (readTime != null) {
                clientBuilder.readTimeout(readTime, TimeUnit.MILLISECONDS);
            }
            OkHttpClient client = clientBuilder.build();

            Request.Builder builder = new Request.Builder();
            fillHeader(builder, headers);

            Request request = builder.url(url).build();
            response = client.newCall(request).execute();
            if (!response.isSuccessful()) {
                return null;
            }
            ResponseBody body = response.body();
            if (body == null) {
                return null;
            }
            return body.string();
        } catch (Throwable e) {
            e.printStackTrace();
            return null;
        } finally {
            CloseUtil.close(response);
        }
    }

	/**
	 * @param readTime 超时时间
	 * @return 返回内容
	 */
	public static byte[] getForBytes(String url, Map<String, String> headers, Long readTime) {
		Response response = null;
		try {
			OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder();
			if (readTime != null) {
				clientBuilder.readTimeout(readTime, TimeUnit.MILLISECONDS);
			}
			OkHttpClient client = clientBuilder.build();

			Request.Builder builder = new Request.Builder();
			fillHeader(builder, headers);

			Request request = builder.url(url).build();
			response = client.newCall(request).execute();
			if (!response.isSuccessful()) {
				return null;
			}
			ResponseBody body = response.body();
			if (body == null) {
				return null;
			}
			return body.bytes();
		} catch (Throwable e) {
			e.printStackTrace();
			return null;
		} finally {
			CloseUtil.close(response);
		}
	}

    /**
     * @param readTime 超时时间
     * @return 返回内容，记得调用close
     */
    public static Response getResponse(String url, Map<String, String> headers, Long readTime) {
        try {
            OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder();
            if (readTime != null) {
                clientBuilder.readTimeout(readTime, TimeUnit.MILLISECONDS);
            }
            OkHttpClient client = clientBuilder.build();

            Request.Builder builder = new Request.Builder();
            fillHeader(builder, headers);

            Request request = builder.url(url).build();
            Response response = client.newCall(request).execute();
            return response;
        } catch (Throwable e) {
            e.printStackTrace();
            return null;
        }
    }

    public static String postFrom(String url, Map<String, String> params) {
        Response response = null;
        try {
            OkHttpClient client = new OkHttpClient();
            StringBuilder sb = new StringBuilder();
            //设置表单参数
            for (String key : params.keySet()) {
                sb.append(key).append("=").append(params.get(key)).append("&");
            }
            RequestBody requestBody = RequestBody.create(sb.toString(), FORM_CONTENT_TYPE);

            //创建请求
            Request request = new Request.Builder()
                    .url(url)
                    .post(requestBody)
                    .build();
            response = client.newCall(request).execute();
            if (response.isSuccessful()) {
                ResponseBody body = response.body();
                if (body != null) {
                    return body.string();
                }
            }
            return null;
        } catch (Throwable e) {
            return null;
        } finally {
            CloseUtil.close(response);
        }
    }

    public static String postJson(String url, String postBody) {
        return postJson(url, null, postBody, null);
    }

    public static String postJson(String url, Map<String, String> headers, String postBody) {
        return postJson(url, headers, postBody, null);
    }

	public static String postJson(String url, String postBody, Integer timeOut) {
		return postJson(url, null, postBody, timeOut);
	}

    public static String postJson(String url, Map<String, String> headers, String postBody, Integer timeOut) {
        Response response = null;
        try {
            OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder();
            if (timeOut != null) {
                clientBuilder.connectTimeout(timeOut, TimeUnit.SECONDS);
                clientBuilder.readTimeout(timeOut, TimeUnit.SECONDS);
            }
            OkHttpClient client = clientBuilder.build();
            Request.Builder builder = new Request.Builder().url(url);
            if (headers != null) {
                //header参数
                for (Map.Entry<String, String> entry : headers.entrySet()) {
                    builder.addHeader(entry.getKey(), entry.getValue());
                }
            }
            Request request = builder.post(RequestBody.create(postBody, MEDIA_TYPE_JSON)).build();
            response = client.newCall(request).execute();
            if (response.isSuccessful()) {
                ResponseBody body = response.body();
                if (body != null) {
                    return body.string();
                }
            }
            return null;
        } catch (Throwable e) {
            return null;
        } finally {
            CloseUtil.close(response);
        }
    }

    public static Response postJsonR(String url, String postBody) {
        try {
            OkHttpClient client = new OkHttpClient();
            Request request = new Request.Builder()
                    .url(url)
                    .post(RequestBody.create(postBody, MEDIA_TYPE_JSON))
                    .build();
            Response response = client.newCall(request).execute();
            if (response.isSuccessful()) {
                return response;
            }
            return null;
        } catch (Throwable e) {
            return null;
        }
    }

    public static Headers head(String url, Map<String, String> headers, int tryCount) {
        for (int i = 0; i < tryCount; i++) {
            Response response = null;
            try {
                OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder()
                        .followRedirects(false)
                        .followSslRedirects(false);
                OkHttpClient client = clientBuilder.build();

                Request.Builder builder = new Request.Builder();
                fillHeader(builder, headers);

                Request request = builder.url(url).build();
                response = client.newCall(request).execute();
                return response.headers();
            } catch (Throwable e) {
                e.printStackTrace();
            } finally {
                CloseUtil.close(response);
            }
        }
        return null;
    }

    public static File downloadFile(String url, File dest, boolean check404, int tryCount) {
        for (int i = 0; i < tryCount; i++) {
            if (dest.exists() && !dest.delete()) {
                continue;
            }
            try {
                OkHttpClient client = new OkHttpClient();
                Request.Builder builder = new Request.Builder();
                Request request = builder.url(url).build();
                Response response = client.newCall(request).execute();
                if (check404) {
                    if (!response.isSuccessful()) {
                        throw new Exception("下载失败 response.isSuccessful() 不成功。url=" + url + " http status code=" + response.code());
                    }
                }
                ResponseBody body = response.body();
                if (body == null) {
                    throw new Exception("下载失败 body为空");
                }

                Sink sink = Okio.sink(dest);
                BufferedSink bufferedSink = Okio.buffer(sink);
                bufferedSink.writeAll(response.body().source());
                bufferedSink.close();

                if (!dest.exists()) {
                    throw new Exception("下载失败，下载之后文件不存在。url=" + url);
                }
                if (dest.length() <= 0) {
                    throw new Exception("下载失败，下载会后的文件大小为0. url=" + url);
                }

                //  做检测, 检测是否下载正确
                try {
                    String contentLength = response.header("Content-Length");
                    if (contentLength != null) {
                        if (!String.valueOf(dest.length()).equals(contentLength)) {
                            continue;
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return dest;

            } catch (Throwable e) {
//                e.printStackTrace();
                ThreadUtils.sleep(1000);
            }
        }
        return null;
    }

    private static void fillHeader(Request.Builder builder, Map<String, String> headers) {
        if (headers != null) {
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                builder.header(entry.getKey(), entry.getValue());
            }
        }
    }

    private static String buildUrlQuery(List<Pair<String, String>> querys) {
        try {
            StringBuilder sbQuery = new StringBuilder();
            if (null != querys) {
                for (Pair<String, String> query : querys) {
                    if (0 < sbQuery.length()) {
                        sbQuery.append("&");
                    }
                    if (String.valueOf((query.getKey())).equals("null") && !query.getValue().equals("null")) {
                        sbQuery.append(query.getValue());
                    }
                    if (!String.valueOf((query.getKey())).equals("null")) {
                        sbQuery.append(query.getKey());
                        if (!String.valueOf(query.getValue()).equals("null")) {
                            sbQuery.append("=");
                            sbQuery.append(URLEncoder.encode(query.getValue(), "utf-8"));
                        }
                    }
                }
            }

            return sbQuery.toString();
        } catch (Throwable e) {
            return "";
        }
    }

    private static String uncompressGzip(byte[] bytes) {
        if (bytes == null || bytes.length == 0) {
            return null;
        }
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        ByteArrayInputStream in = new ByteArrayInputStream(bytes);
        try {
            GZIPInputStream ungzip = new GZIPInputStream(in);
            byte[] buffer = new byte[256];
            int n;
            while ((n = ungzip.read(buffer)) >= 0) {
                out.write(buffer, 0, n);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return new String(out.toByteArray());
    }

}